<?

/*  This collection of functions (libary) is licensed under GPL2.
    See LICENSE or www.gnu.org for more details.

    Define here the functions that produce the code for custom features.
    This code is then inserted in the head script if needed.

    Functions here are called from dzScriptSeppo whenever it meets a feature
    which type is custom.
    
    Every function that is accessed outside this file has a prefix 'dzCf' and
    functions must return a string containing the piece of that is inserted
    to the head script by dzScriptSeppo. Functions here can have any number 
    of arguments because the call must still be hard coded in dzScriptSeppo.
    
    Adding a custom feature:
    1)  Define the feature in dzfeatures.ini. Set the 'Custom'-key to 
        value 'yes'
    2)  Write here the code that produces the special script that
        makes the feature
    3)  Add a call to the function defined here into dzSeppo.php source
        file in the switch clause in the function makeCustomFeature($Name).
        Where the $Name is the name of the feature.
*/

if (DZCUSTOMFEAT == "") return;
define(DZCUSTOMFEAT, "");

include_once("dzconst.php");
include_once("dzstonga.php");
include_once("dzmenu.php");
include_once("sodebug.php");
include_once("sogeneric.php");

    /*
     * Creates the RoamingMap data structure for JavaScript. This is used by 
     * event handlers to decide where to move from the widget.
     *  >$Widgets:array/str   The list of the widgets on the form
     *  <:str    Produced script
     */
    function dzCfRoamMap($Widgets) {
        $result = "";

        $row = 0; $s="";
    /* Get the list of widgets on the form. 
                 The syntax of widget name is
                 n_g_y_x_name_e
                 where
                 n: either s, e or n, 
                   s single widget
                   e expandable table widget. Not the new line
                   n signalling that this widget is on the last
                     row on a dataz table (expandable rows).
                 g: group id (table no.)
                 y: similar destiny for y direction.
                 x: x coordinate of the widget
                 name: Column name on the server side
                 e: either c or i, is this field calculated field
                    c calculated field
                    n normal field (not calculated)
     */
        $icount = count($Widgets);
        for ($c = 0; $c < $icount; $c++) {
            /* Extract the row number of the next component */
            $newRow = soExtractVal($Widgets[$c], "_", 3);
            
            /* If the row has changed start a new row in the 
               roaming map as well */
            if ($newRow != $row) {
                $tmp = "CompMap[$row] = [$s];";
                $result = soJoinStr($result, "\n", $tmp, 1);
                $row = $newRow; $s = "";
            } // if
            $s = soJoinStr($s, ",", "'".$Widgets[$c]."'", 1);
        } // for
        $tmp = "CompMap[$row] = [$s];";
        $result = soJoinStr($result, "\n", $tmp, 1);
        
        /* Add map end marker */
        $row++;
        $tmp = "CompMap[".$row."] = []; //this marks the end of the array";
        $result = soJoinStr($result, "\n", $tmp, 1);
    
        /* Insert map size in the beginning of the produced script */
        $row++;
        $tmp = "CompMap = new Array(".$row.");";
        $result = soJoinStr($result, "\n", $tmp, 0);

        return $result;
    } //  dzCfRoamMap

        
    /*
     *  Produce the script that creates the Stonga when the Nalle
     *  is loaded by the client side. This is located in the head
     *  script section and executed by the client while Nalle loads.
     *  
     *  >$Template:dzTemplate  Pointer to form data
     *  >$Views:dzTemplate  The list of the open views
     *  <:str    Produced script
     */
    function dzCfMakeStonga(&$Template, $Views) {
        soDebug("dzCfMakeStonga: creating stonga", SOD_DET);

        $script = dzMakeStonga($Template, $Views);

        return $script;
    } // dzCfMakeStonga


    /**
     *  Creates the script that creates the menu.
     *  >$UserLevel:int     The level that the user has
     *  <:str    Produced script
     */
    function dzCfMakeMenu($UserLevel, $Language = "default") {
        soDebug("dzCfMakeMenu: creating menu", SOD_DET);
        $menu = new dzMenu();
        return $menu->getMenu($UserLevel, "", $Language);
    } // dzCfMakeMenu


    /**
     * Create data structures needed to implement calculate fields. This is
     * dependency lists and formulas assigned to fields.
     * >$Formulas:array/str  formulas for the calculated fields
     * >$DepFields:array/soSet/str  Field dependecies
     * <:str    Produced script
     */
    function dzCfCalculateFields($Formulas, $DepFields) {
        soDebug("dzCfCalculateFields: entered", SOD_DET);
        $result = "// Formulas for the calculated fields\n";
        /* Produce first the formulas to insert into headscript */
        $fcount = count($Formulas);
        soDebug("dzCfCalculateFields: $fcount formulas exists", SOD_DET);
        foreach ($Formulas as $equation) {
            $target = soExtractVal($equation, "=", 1);
            $formula = soExtractVal($equation, "=", 2);
            $result .= "formula_".$target." = \"".$formula."\";\n";
        } // for

        /* Produce the dependency lists added into the head script */
        $result .= "\n// Dependecies for the fields\n";

        foreach ($DepFields as $key => $val) {
            $s = getDeps($key, $DepFields);
            $result .= "dzDep_$key = Array(".$s.");\n";
        } // foreach

        return $result;
    } // dzCfCalculateFields


    /**
     * Find out the dependency chain for a given field.
     * >$Field:str    The name of field which dependency chain to seek
     * >$DepArr:Array/soSet    The array of all dependecies.
     * <:str    The dependency chain for the given field as a string. Field
     * names are closed in "'"-marks and separated with comma.
     */
    function getDeps($Field, $DepArr) {
        soDebug("dzCustomFeature: getDeps($Field, ...) ", SOD_DET);
        $s = '';
        /* Get the set of dependencies this field has*/
        $fieldDepsSet = $DepArr[$Field];
        /* Check that there is still dependecies */
        if (is_object($fieldDepsSet)) {
            $fieldDepsArr = $fieldDepsSet->getAsArray();
            /* Iterate through all the depending fields */
            while (list ($depField, $none) = each ($fieldDepsArr)) {
                $s = soJoinStr($s, ",", "'$depField'", 1);
                /* Call myself again to find out the dependencies for the current field */
                $subDep = getDeps($depField, $DepArr);
                /* If there was any dependencies join them to the chain */
                if ($subDep != "")
                    $s = soJoinStr($s, ",", $subDep, 1);
            } // while
        }

        return $s;
    } // getDeps


    /**
     * Constructs the data structures needed to implement after change events
     * >$FieldList:array/str  List of fields where after change event is defined
     * <:str    Produced script
     */
    function dzCfAfterChange($FieldList) {
        soDebug("dzCfAfterChange: entered", SOD_DET);
        $result = "";
        while (list($fieldName, $function) = each ($FieldList)) {
            $result .= "dzAC_".$fieldName."=\"".$function."\";\n";
        } // while
        
        return $result;
    } // dzCfAfterChange


    /**
     * Constructs the data structures needed to implement field validation.
     * These structures what columns have validation and what kind of 
     * validation that is
     * >$FieldList:array/str List of the fields that has field validation
     *                       defined.
     * <:str    Produced script
     */
    function dzCfFieldValidation($FieldList) {
        soDebug("dzCfFieldValidation: entered", SOD_DET);
        $result = "";
        while (list($fieldName, $function) = each ($FieldList)) {
            $result .= "dzValidate_".$fieldName."=\"".$function."\";\n";
        } // while
        
        return $result;
    } // dzCfFieldValidation


    /**
     *  Constructs the data structures needed to implement type checking.
     *  The constructed constants contains the field type, length and ranges.
     *  The informaton is read from the Datazet source. The format is following:
     *  <type>;[<length>];[<range>;[<range>...]]
     *  type = int/char/dec/time/date
     *  length applies only with dec and char. When type is dec the length means
     *  the number of the decimals.
     *  Ranges are optional and applies only with int and dec.
     *  NOTE: time & date have no type checking yet.
     *
     * >$FieldList:array/str  The list of the fields that has type checking
     * <:str    Produced script
     */
    function dzCfTypeCheck($FieldList) {
        soDebug("dzCfTypeCheck: entered", SOD_DET);
        $result = "";
        while (list($fieldName, $info) = each ($FieldList)) {
            /* No periods allowed in the field names.*/
            $widget_name = soSwapStr($fieldName, ".",
                                     DZ_FIELD_SUBSTITUTION_CHAR);
            $result .= "dzType_".$fieldName."=\"".$info."\";\n";
        } // while

        return $result;
    } // dzCfTypeCheck


    /**
     * Make JavaScript data structures where is stored the new line fields.
     * these are the fields at the last row in group/pot in edit and new modes
     * and used to add new rows to database. Column can be required aswell.
     * In JS when the focus is lost from a field that is type of insert field,
     * then all required fields are checked. If all of them have a value then the
     * insert new row event is triggered.
     *
     * This custom feature function construct data structures needed to implement
     * new fields.
     *
     * >$NewFieldSet:soSet/array/str   The list of the fields that triggers
     *                                  the new row event
     * >$ReqFieldSet:soset/array/str    Columns that must be filled before
     *                                  the row insertion event is triggered.
     * <:str    Produced script
     */
    function dzCfNewLine($NewFieldSet, $ReqFieldSet) {
        soDebug("dzCfNewLine: entered", SOD_DET);
        if (soGetClass($NewFieldSet) != "soset") return ""; // <-- EXIT!!

        $newArr = $NewFieldSet->getAsArray();
        while (list ($potNo, $newfields) = each ($newArr)) {
            $fcount = count($newfields);
            for ($c = 0; $c < $fcount; $c++) {
                $result .= "dzNewFld_".$newfields[$c]." = new Array(";
                $s = "";
                if ($ReqFieldSet->itemExists($potNo)) {
                    $reqFields = $ReqFieldSet->getItem($potNo);
                    $rcount = count($reqFields);
                    for ($r = 0; $r < $rcount; $r++) {
                        $s = soJoinStr($s, ",", "'".$reqFields[$r]."'");
                    } // for ($r...)
                }
                $result .= $s.");\n";
            } // for ($c...)
        } //while

        return $result;
    } // dzCfNewLine


    /**
     * Make JavaScript arrays that lists the filter seed groups and columns.
     * These are used to trigger filter change event from the form.
     *
     * >$FilterSeedGroups:array/str Array of groups that cpntins filter
     *                    seed columns
     * >$FilterSeedCols:array/str Array os filter seeds
     */
    function dzCfFilterGroup($FilterSeedGroups, $FilterSeedCols) {
        soDebug("dzCfFilterGroup: entered", SOD_DET);

        $item_list = "";
        foreach ($FilterSeedGroups as $group_name) {
            $item_list = soJoinStr($item_list, ",", "$group_name");
        } // foreach

        foreach ($FilterSeedCols as $col_name) {
            $item_list = soJoinStr($item_list, ",", "$col_name");
        } // foreach

        $item_list = "tt,ze";
        $result .= "var FilterEventSources = '$item_list';\n";

        return $result;
    } // dzCFFilterGroup

?>